/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.collections.tuples;

import static com.softwarecraftsmen.collections.tuples.Quadruple.quadruple;
import static com.softwarecraftsmen.collections.tuples.Quintuple.quintuple;
import static com.softwarecraftsmen.collections.tuples.Septuple.septuple;
import static com.softwarecraftsmen.collections.tuples.Sextuple.sextuple;
import static com.softwarecraftsmen.collections.tuples.Triple.triple;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.LinkedList;
import java.util.ArrayList;

public class Pair<A, B> extends AbstractTuple
{
	@NotNull
	public final A a;
	@NotNull
	public final B b;

	private Pair(final @NotNull A a, final @NotNull B b)
	{
		super();
		this.a = a;
		this.b = b;
	}

	@NotNull
	public static <A, B> Pair<A, B> pair(@NotNull final A a, @NotNull final B b)
	{
		return new Pair<A, B>(a, b);
	}

	@NotNull
	public static <K, V> Pair<K, V> fromLegacyEntry(@NotNull final Map.Entry<K, V> legacyMapEntry)
	{
		return new Pair<K, V>(legacyMapEntry.getKey(), legacyMapEntry.getValue());
	}

	@NotNull
	public <C> Triple<A, B, C> append(@NotNull final C c)
	{
		return triple(a, b, c);
	}

	@NotNull
	public <C, D> Quadruple<A, B, C, D> append(@NotNull final C c, @NotNull final D d)
	{
		return quadruple(a, b, c, d);
	}

	@NotNull
	public <C, D, E> Quintuple<A, B, C, D, E> append(@NotNull final C c, @NotNull final D d, @NotNull final E e)
	{
		return quintuple(a, b, c, d, e);
	}

	@NotNull
	public <C, D, E, F> Sextuple<A, B, C, D, E, F> append(@NotNull final C c, @NotNull final D d, @NotNull final E e, @NotNull final F f)
	{
		return sextuple(a, b, c, d, e, f);
	}

	@NotNull
	public <C, D, E, F, G> Septuple<A, B, C, D, E, F, G> append(@NotNull final C c, @NotNull final D d, @NotNull final E e, @NotNull final F f, @NotNull final G g)
	{
		return septuple(a, b, c, d, e, f, g);
	}

	@NotNull
	public Object valueAt(final Integer index)
	{
		guardValueAt(index);
		switch(index)
		{
			case 0:
				return a;
			case 1:
				return b;
			default:
				throw new IllegalStateException();
		}
	}


	@NotNull
	public ArrayList<Object> toLegacyArrayList()
	{
		return (ArrayList<Object>) addToList(super.toLegacyArrayList());
	}

	@NotNull
	public LinkedList<Object> toLegacyLinkedList()
	{
		return (LinkedList<Object>) addToList(super.toLegacyLinkedList());
	}

	private List<Object> addToList(final List<Object> list)
	{
		list.add(a);
		list.add(b);
		return list;
	}

	public int size()
	{
		return 2;
	}

	@NotNull
	public String toString()
	{
		return String.format(Locale.UK, "(%1$s, %2$s)", a, b);
	}

	public boolean equals(final Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (o == null || getClass() != o.getClass())
		{
			return false;
		}

		final Pair pair = (Pair) o;

		return a.equals(pair.a) && b.equals(pair.b);
	}

	public int hashCode()
	{
		int result;
		result = a.hashCode();
		result = 31 * result + b.hashCode();
		return result;
	}

	@NotNull
	public Singleton<A> slice()
	{
		return tuple(a);
	}
}
